package com.magi.builder;

import com.magi.config.BuildingConfig;
import com.magi.config.IJavaPojoBuildingConfig;
import com.magi.constant.DatabaseProducts;
import com.magi.constant.TypeMappingFileNames;
import com.magi.core.*;
import com.magi.exception.TypeMappingNotFoundException;
import org.dom4j.DocumentException;

import java.util.ArrayList;
import java.util.List;

public class JavaPojoBuilder implements IJavaPojoBuilder{
    private final IDatabaseTypeMapping typeMapping;
    private JavaFileBuilder builder;
    private final IJavaPojoBuildingConfig config;

    public JavaPojoBuilder(IJavaPojoBuildingConfig config) throws DocumentException {
        this.config = config;
        if (config.getDatabaseProductName().equals(DatabaseProducts.MYSQL)) {
            this.typeMapping = new DatabaseTypeMapping(TypeMappingFileNames.MYSQL);
            return;
        }
        throw new RuntimeException("Unsupported database product " + config.getDatabaseProductName());
    }

    @Override
    public String Build(TableMetaData metaData) throws TypeMappingNotFoundException {
        String pojoName = AppUtils.tableName2className(metaData.getTableName());
        builder = new JavaFileBuilder();
        builder.addPackage(config.getRootPojoPackageName());

        ClassMetaData classMetaData = AppUtils.tableMetaData2classMetaData(metaData, typeMapping);
        List<ClassMetaData.Field> fields = classMetaData.getFields();
        for (ClassMetaData.Field field : fields) {
            String neededPackage = typeMapping.getJavaTypePackage(field.getType());
            if (neededPackage != null) {
                builder.importPackage(neededPackage);
            }
        }

        builder.addClass(pojoName);

        for (ClassMetaData.Field field : fields) {
            this.addField(field);
        }

        builder.newLine();

        for (ClassMetaData.Field field : fields) {
            this.addSetter(field);
            builder.newLine();
            this.addGetter(field);
            builder.newLine();
        }

        return builder.finish();
    }

    private void addField(ClassMetaData.Field field) {
        builder.addField(JavaFileBuilder.Qualifiers.PRIVATE,
                field.getName(),
                field.getType(),
                null,
                null);
    }

    private void addSetter(ClassMetaData.Field field) {
        builder.addFunction(JavaFileBuilder.Qualifiers.PUBLIC,
                "set" + AppUtils.lowerCamel2upperCamel(field.getName()),
                new JavaFileBuilder.FunctionArg[]{
                        new JavaFileBuilder.FunctionArg(field.getType(), field.getName())
                },
                Identifiers.TAB + "this." + field.getName() + " = " + field.getName() + Identifiers.SEMICOLON, null);
    }

    private void addGetter(ClassMetaData.Field field) {
        builder.addFunction(JavaFileBuilder.Qualifiers.PUBLIC,
                "get" + AppUtils.lowerCamel2upperCamel(field.getName()),
                new JavaFileBuilder.FunctionArg[]{
                        new JavaFileBuilder.FunctionArg(field.getType(), field.getName())
                },
                Identifiers.TAB + "return this." + field.getName() + Identifiers.SEMICOLON,
                field.getType());
    }

    @Override
    public String text() {
        return builder.text();
    }

    public static void main(String[] args) throws DocumentException, TypeMappingNotFoundException {
        IJavaPojoBuilder builder = new JavaPojoBuilder(new BuildingConfig());
        builder.Build(new TableMetaData("test_table", new ArrayList<TableMetaData.Column>() {
            {
                add(new TableMetaData.Column("VARCHAR", "test_col"));
                add(new TableMetaData.Column("VARCHAR", "test_col2"));
            }
        }));
        System.out.println(builder.text());
    }
}
